package com.sky.aspect;

import com.sky.annotation.Autofill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import com.sky.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @Description TODO
 * @Author itheima
 * @Date 2023-07-10 14:54
 */
@Slf4j
@Component//加入容器
@Aspect//声明这个类是切面类
public class AutoFillAspect {
    /**
     *  切入点表达式, @Pointcut的作用试讲公共的切入点表达式抽取出来,需要时引用即可
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..))&& @annotation(com.sky.annotation.Autofill)")
    public  void  autofillpointcut(){}
    @Before("autofillpointcut()")//切面
    //在Spring中用JoinPoint抽象了连接点，用它可以获得方法执行时的相关信息，如目标类名、方法名、方法参数
    public  void  autoFill(JoinPoint joinPoint){
            log.info("开始公共字段填充");
        /*思路 获取注解和注解的属性值 获取原始方法的参数---------->进行一个安全的判断判断原始参数数组是否有效,有效获取参数第一个对象,无效报异常
         * 根据autofill获取volue属性值判断是新增还是修改  ---->新增填充
         * 根据反射得到set方法执行set方法 ,填充数据------>修改填充----->返回结果
         * */
        try {
            //获取方法签名时对象
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获得方法上的注解对象  参数 自定义注解的字节码文件Autofill.class
            Autofill annotation = signature.getMethod().getAnnotation(Autofill.class);
            //根据注解对象获取波略属性值
            OperationType value = annotation.value();
            //获取原始方法的参数
            Object[] args = joinPoint.getArgs();
            //判断原始方法的数组是否有效,无效返回结束
            if (args==null||args.length==0){
                return;
            }
            //获取原始方法第一个参数-->实体类的对象
            Object arg = args[0];
            //获取字节码文件
            Class aClass = arg.getClass();
            //通过反射获取方法

            Method declaredMethod3 = aClass.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            Method declaredMethod2 = aClass.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            //通过invoke()api进行赋值
            declaredMethod3.invoke(arg,BaseContext.getCurrentId());
            declaredMethod2.invoke(arg,LocalDateTime.now());
            //判断是增加操作还是修改操作
            if (OperationType.INSERT==value){
                Method declaredMethod = aClass.getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method declaredMethod1 = aClass.getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                declaredMethod.invoke(arg,LocalDateTime.now());
                declaredMethod1.invoke(arg, BaseContext.getCurrentId());

            }
        } catch (Exception e) {
            e.printStackTrace();
            //抛出异常自定义异常能被全局异常处理器捕获到
            throw new BaseException(e.getMessage());
        }

    }

}
